package com.hl3hl3.arcoremeasure.renderer;

import android.opengl.GLES20;
import android.opengl.Matrix;

import com.google.ar.core.examples.java.helloar.rendering.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * Created by user on 2017/9/26.
 */

public class RectanglePolygonRenderer {

    private FloatBuffer vertexBuffer;
    private ShortBuffer drawListBuffer;

    // number of coordinates pervertex in this array
    static final int COORDS_PER_VERTEX = 3;
    static float coords[] = {
            -0.6f,  0.5f, 0.2f,   // top left
            -0.4f, -0.5f, 0.2f,   // bottom left
            0.5f, -0.5f, 0.2f,   // bottom right
            0.5f,  0.5f, 0.2f,   // top right

            -0.5f,  0.6f, 0.0f,   // top left
            -0.5f, -0.8f, 0.0f,   // bottom left
            0.5f, -0.5f, 0.0f,   // bottom right
            0.5f,  0.5f, 0.0f   // top right
    };
    private short drawOrder[] = {
            0, 1, 2,  0, 2, 3,
            3, 2, 6,  3, 6, 7,
            4, 5, 6,  4, 6, 7,
            0, 1, 5,  0, 5, 4,
            4, 0, 3,  4, 3, 7,
            5, 1, 2,  5, 2, 6
    }; // order to draw vertex

    float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};

    public void setVerts(float v0, float v1, float v2,
                         float v3, float v4, float v5,
                         float v6, float v7, float v8,
                         float v9, float v10, float v11,

                         float v12, float v13, float v14,
                         float v15, float v16, float v17,
                         float v18, float v19, float v20,
                         float v21, float v22, float v23
                         ) {
        coords[0] = v0;
        coords[1] = v1;
        coords[2] = v2;

        coords[3] = v3;
        coords[4] = v4;
        coords[5] = v5;

        coords[6] = v6;
        coords[7] = v7;
        coords[8] = v8;

        coords[9] = v9;
        coords[10] = v10;
        coords[11] = v11;

        coords[12] = v12;
        coords[13] = v13;
        coords[14] = v14;

        coords[15] = v15;
        coords[16] = v16;
        coords[17] = v17;

        coords[18] = v18;
        coords[19] = v19;
        coords[20] = v20;

        coords[21] = v21;
        coords[22] = v22;
        coords[23] = v23;

        vertexBuffer.put(coords);
        // set the buffer to read the first coordinate
        vertexBuffer.position(0);
    }

    public void setColor(float red, float green, float blue, float alpha) {
        color[0] = red;
        color[1] = green;
        color[2] = blue;
        color[3] = alpha;
    }


    private final int mProgram;

    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "}";

    // Use to access and set the view transformation
    private int mMVPMatrixHandle;

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private int mPositionHandle;
    private int mColorHandle;

    private final int vertexCount = coords.length / COORDS_PER_VERTEX;
    private final int vertexStride = COORDS_PER_VERTEX * 4;

    private int loadShader(int type, String shaderCode){
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    public RectanglePolygonRenderer(){
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(coords);
        vertexBuffer.position(0);

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);   // 2 bytes per short
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        // create empty OpenGL ES Program
        mProgram = GLES20.glCreateProgram();

        // add the shader to program
        GLES20.glAttachShader(mProgram, vertexShader);
        GLES20.glAttachShader(mProgram, fragmentShader);

        // create OpenGL ES program executables
        GLES20.glLinkProgram(mProgram);
        Matrix.setIdentityM(mModelMatrix, 0);
    }

    // Temporary matrices allocated here to reduce number of allocations for each frame.
    private float[] mModelMatrix = new float[16];
    private float[] mModelViewMatrix = new float[16];
    private float[] mModelViewProjectionMatrix = new float[16];
    final String TAG = "RectanglePolygon";

    public void draw(float[] cameraView, float[] cameraPerspective) {
        ShaderUtil.checkGLError(TAG, "Before draw");

        // Build the ModelView and ModelViewProjection matrices
        // for calculating object position and light.
        Matrix.multiplyMM(mModelViewMatrix, 0, cameraView, 0, mModelMatrix, 0);
        Matrix.multiplyMM(mModelViewProjectionMatrix, 0, cameraPerspective, 0, mModelViewMatrix, 0);

        // add program to OpenGL ES environment
        GLES20.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        // enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        // set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);

        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

        // Pass the projection and view transformation to the shader
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mModelViewProjectionMatrix, 0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}
